Sql Server系列:嵌套查询
嵌套查询是指一个查询语句嵌套在另一个查询语句内部的查询。嵌套查询也就子查询,在SELECT子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或多个表。子查询中可以使用比较运算符,如“<”、“<=”、“>”、“>=”等。
子查询中常用的操作符有ANY(SOME)、ALL、EXISTS。子查询可以添加到SELECT 、UPDATE和DELETE语句中,可以进行多层嵌套。
1 使用比较运算符
子查询使用比较运算符,如“<”、“<=”、“>”、“>=”等。
示例:返回单个值的SELECT语句的嵌套查询
SELECT * FROM [dbo].[Product] WHERE [UnitPrice] = ( SELECT MIN([UnitPrice]) FROM [dbo].[Product] )
SELECT * FROM [dbo].[Product] WHERE [CategoryID] = ( SELECT [CategoryID] FROM [dbo].[Category] WHERE [CategoryName] = 'LINQ to SQL' )
2. 使用IN关键字
IN关键字进行子查询时,内层查询语句仅仅返回一个数据列,这个数据列里的值将提供给外层查询语句进行比较。
示例:返回多个值的子查询的嵌套查询
SELECT * FROM [dbo].[Product] WHERE [CategoryID] IN ( SELECT [CategoryID] FROM [dbo].[Category] WHERE [CategoryID] <= 10 )
尽管使用IN的嵌套查询方式可以实现,但更好的方式是使用内连接实现这种查询,而不是使用使用嵌套的SELECT。
上例的子查询使用INNER JOIN方式:
SELECT [dbo].[Product].* FROM [dbo].[Product] INNER JOIN [dbo].[Category] ON [dbo].[Product].[CategoryID] = [dbo].[Category].[CategoryID] WHERE [dbo].[Category].[CategoryID] <= 10
出于性能方面的考虑,如果没有特别的理由要使用嵌套的SELECT,则还是应使用连接方式作为默认的解决方案。在大部分情况下,SQL Server会将嵌套子查询解决方案解析为和使用连接用于的查询计划,在检查嵌套子查询和内连接查询计划时,会发现它们的完全相同的计划。大多数情况下,这两种方法没有多大的区别。当查询计划不同时,连接通常的更好的选择。
SELECT语句中可以使用NOT IN运算符,其作用与IN相反。
3. ANY、SOME关键字
ANY和SOME关键字是同义词,表示满足其中任一条街。它们允许创建一个表达式对子查询的返回值列表进行比较,只要满足内层子查询中任何一个比较条件,就返回一个结果作为外层查询的条件。
ANY关键字接在一个比较操作符的后面,表示与子查询返回的任何值比较为TRUE,则返回TRUE。
示例:
IF 20 > ANY ( SELECT [UnitsInStock] FROM [dbo].[Product] ) PRINT '1' ELSE PRINT '0'
4. ALL关键字
ALL关键字用于需要同时满足所有内层查询的条件,只有当子查询返回的所有值比较都为TRUE,才返回TRUE。
示例:
IF 20 > ALL ( SELECT [UnitsInStock] FROM [dbo].[Product] ) PRINT '1' ELSE PRINT '0'
5. EXISTS关键字
EXISTS关键字后面的参数是一个任意的子查询,系统对子查询进行运算以判断它是否返回行,如果至少返回一行,则EXISTS的结果为TRUE,此时外层查询语句将进行查询;如果子查询没有返回任何行,那么EXISTS返回的结果是FALSE,此时外层语句将不进行查询。
示例:
SELECT * FROM [dbo].[Category] WHERE EXISTS ( SELECT * FROM [dbo].[Product] WHERE [CategoryID] = 1 )
EXISTS关键字还可以和条件表达式一起使用。
SELECT * FROM [dbo].[Category] WHERE [CategoryName] ='LINQ to SQL' AND EXISTS ( SELECT * FROM [dbo].[Product] WHERE [CategoryID] = 1 )
NOT EXISTS与EXISTS使用方法相同,返回的结果相反。
SELECT * FROM [dbo].[Category] WHERE NOT EXISTS ( SELECT * FROM [dbo].[Product] WHERE [CategoryID] = 1 )
Exists关联子查询:查询所有存在Product的Category
SELECT * FROM [dbo].[Category] c WHERE EXISTS ( SELECT * FROM [dbo].[Product] p WHERE p.[CategoryID] = c.[CategoryID] )
上例同样可以使用INNER JOIN实现:
SELECT c.* FROM [dbo].[Category] c INNER JOIN [dbo].[Product] p ON p.[CategoryID] = c.[CategoryID]
基于连接的语法可以得到相同的结果,但使用EXISTS具有更好的性能。使用EXISTS关键字,SQL Server不需要执行一行一行的完全连接,而是直接寻找记录,直到找到第一个匹配的记录。